package org.example.handler;

import cn.hutool.core.stream.CollectorUtil;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolationException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.example.result.R;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.ErrorResponse;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;


import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理业务逻辑异常
     */
    @ExceptionHandler(BusinessException.class)
    public R handleBusinessException(BusinessException ex,
                                                                 HttpServletRequest request) {
        log.warn("业务异常: {} - {}", ex.getErrorCode(), ex.getMessage());

        return R.error().setCode(ErrorCode.SERVER_ERROR.code)
                .setData(Collections.singletonMap("errorCode", ex.getErrorCode()))
                .setMessage(ex.getMessage());
    }

    /**
     * 处理参数校验异常（@Validated）
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R handleMethodArgumentNotValid(
            MethodArgumentNotValidException ex, HttpServletRequest request) {

        List<String> errors = ex.getBindingResult().getFieldErrors().stream()
                .map(error -> error.getField() + ": " + error.getDefaultMessage())
                .collect(Collectors.toList());

        String errorMessage = "参数校验失败: " + String.join("; ", errors);
        log.warn(errorMessage);



        return R.error().setCode(ErrorCode.INVALID_PARAMETER.code)
        .setMessage(ErrorCode.INVALID_PARAMETER.description);


    }

    /**
     * 处理参数绑定异常（@ModelAttribute）
     */
    @ExceptionHandler(BindException.class)
    public R handleBindException(BindException ex,
                                                             HttpServletRequest request) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error ->
                errors.put(error.getField(), error.getDefaultMessage()));

        String errorMessage = "参数绑定失败: " + errors;
        log.warn(errorMessage);

        return R.error().setCode(ErrorCode.INVALID_PARAMETER.code)
                .setMessage(ErrorCode.INVALID_PARAMETER.description);
    }

    /**
     * 处理参数约束异常（@RequestParam）
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public R handleConstraintViolation(
            ConstraintViolationException ex, HttpServletRequest request) {

        List<String> errors = ex.getConstraintViolations().stream()
                .map(violation -> violation.getPropertyPath() + ": " + violation.getMessage())
                .collect(Collectors.toList());

        String errorMessage = "参数约束失败: " + String.join("; ", errors);
        log.warn(errorMessage);

        return R.error().setCode(ErrorCode.INVALID_PARAMETER.code)
                .setMessage(ErrorCode.INVALID_PARAMETER.description);
    }

    /**
     * 处理认证异常
     */
    @ExceptionHandler({AuthenticationException.class, BadCredentialsException.class})
    public R handleAuthenticationException(
            Exception ex, HttpServletRequest request) {

        log.warn("认证失败: {}", ex.getMessage());

        Throwable cause = ex.getCause();
        if (cause!=null &&cause instanceof BusinessException) {
           return handleBusinessException((BusinessException) cause, request);
        }
        if(ex instanceof BadCredentialsException){
            return R.error().setCode(ErrorCode.UNAUTHORIZED.code)
                    .setMessage(ex.getMessage());
        }
        return R.error().setCode(ErrorCode.UNAUTHORIZED.code)
                .setMessage(ErrorCode.UNAUTHORIZED.description);
    }

    /**
     * 处理授权异常
     */
    @ExceptionHandler(AccessDeniedException.class)
    public R handleAccessDeniedException(
            AccessDeniedException ex, HttpServletRequest request) {

        log.warn("权限不足: {}", ex.getMessage());


        return R.error().setCode(ErrorCode.FORBIDDEN.code)
                .setMessage(ErrorCode.FORBIDDEN.description);
    }

    /**
     * 处理404异常
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public R handleNoHandlerFoundException(
            NoHandlerFoundException ex, HttpServletRequest request) {

        log.warn("资源未找到: {} {}", ex.getHttpMethod(), ex.getRequestURL());
        return R.error().setCode(ErrorCode.NOT_FOUND.code)
                .setMessage(ErrorCode.NOT_FOUND.description);
    }

    /**
     * 处理其他常见异常
     */
    @ExceptionHandler({
            MissingServletRequestParameterException.class,
            MethodArgumentTypeMismatchException.class,
            HttpMessageNotReadableException.class,
            InvalidFormatException.class,
            HttpRequestMethodNotSupportedException.class
    })
    public R handleCommonExceptions(
            Exception ex, HttpServletRequest request) {

        String errorMessage = "请求参数错误";
        if (ex instanceof HttpRequestMethodNotSupportedException) {
            errorMessage = "不支持的HTTP方法";
        } else if (ex instanceof InvalidFormatException) {
            errorMessage = "参数格式错误";
        }

        log.warn("请求异常: {} - {}", ex.getClass().getSimpleName(), ex.getMessage());


        return R.error().setCode(ErrorCode.INVALID_REQUEST.code)
                .setMessage(ErrorCode.INVALID_REQUEST.description);
    }

    /**
     * 处理所有未捕获的异常
     */
    @ExceptionHandler(Exception.class)
    public R handleAllExceptions(
            Exception ex, HttpServletRequest request) {

        log.error("系统异常: {} - {}", request.getRequestURI(), ex.getMessage(), ex);

        return R.error().setCode(ErrorCode.SERVER_ERROR.code)
                .setMessage(ErrorCode.SERVER_ERROR.description);
    }

    /**
     * 错误码枚举
     */
    @AllArgsConstructor
    @Getter
    public enum ErrorCode {
        // 业务错误码
        INVALID_PARAMETER(40001, "参数错误"),
        UNAUTHORIZED(40101, "未授权"),
        FORBIDDEN(40301, "禁止访问"),
        NOT_FOUND(40401, "资源不存在"),
        INVALID_REQUEST(40002, "无效请求"),

        // 系统错误码
        SERVER_ERROR(50001, "系统错误");

        private final int  code;
        private final String description;
    }

    /**
     * 自定义业务异常
     */
    public static class BusinessException extends RuntimeException {
        private final String  errorCode;

        public BusinessException(String  errorCode, String message) {
            super(message);
            this.errorCode = errorCode;
        }

        public String  getErrorCode() {
            return errorCode;
        }
    }
}